#ifndef KEYMGT_H_
#define KEYMGT_H_

#include <stdint.h>
#include "crypto.h"
#define OFFSET(type, member) (uint32_t)(&(((type *)0)->member))

#define XORDATA(j, data1, data2, datalen, outdata) {\
        for( j=0 ; j<(datalen) ; j++ ) \
                (outdata)[j] = (data1)[j]^(data2)[j]; \
}


#define DES3_KEY_LEN                16  /*Triple DES Key len 16bytes*/
#define RSA_KEY_LEN                 256 /*2048bit -> 256bytes*/
#define HASH_RSTLEN		        32		/* the length of HASH result */

/* Key Field ID */
#define KF_MT           0x00            /*Master/Transaction Key*/
#define KF_FIX          0x01            /*Fixed Key*/
#define KF_DUKPT        0x02            /*DUKPT Key*/
#define KF_MAX          KF_DUKPT

/* Key Type ID */
#define KT_MST          0x00            /*Master Key*/
#define KT_PIN          0x01            /*PIN Encryption Key*/
#define KT_MAC          0x02            /*MAC Computing Key*/
#define KT_MAG          0x03            /*MAG Data Key*/
#define KT_MAX          KT_MAG

/* max key groups storage */
#define MT_GRP_MAX              24      /*Master/Transaction Key max group no.*/
#define FIX_GRP_MAX             24      /*Fixed Key max group no.*/
#define DUKPT_GRP_MAX           5       /*DUKPT Key max group no.*/
#if 0
#define MT_GRP_MAX              CONFIG_MT_GROUP         /*Master/Transaction Key max group no.*/
#define FIX_GRP_MAX             CONFIG_FIXED_GROUP      /*Fixed Key max group no.*/
#define DUKPT_GRP_MAX           CONFIG_DUKPT_GROUP      /*DUKPT Key max group no.*/
#endif
#define DUKPT_SET_MAX           21                      /* 21 sets in each group*/
#define DUKPT_KSN_LEN           10                      /*DUKPT KSN LEN*/
#define RXDEV_ID_LEN            16                      /*Device unique ID length*/
#define PUBKEY_REMAINDER_LEN    56
#define PUBKEY_CERT_LEN         242
#define RSA_DEF_EXP             "\x01\x00\x01"
#define RSA_DEF_EXPLEN          3                       /* certificate plain-text length*/

#define MST_GRP_LEN             sizeof (mst_group_t)
#define DUKPT_GRP_LEN           sizeof (dukpt_group_t)
#define MAX_GRP_LEN             ((DUKPT_GRP_LEN > MST_GRP_LEN) ? DUKPT_GRP_LEN : MST_GRP_LEN)

/* keysys_status definition */
#define KEYSYS_STS_SLTESTF                      0x01            /*selftest Fail*/
#define KEYSYS_STS_CRL                          0x02            /*CRL exist*/
#define KEYSYS_STS_SESSION                      0x04            /*a session started*/
#define KEYSYS_STS_CHKSERR                      0x08            /*Key Checksum ERR*/
#define KEYSYS_STS_BUSY                         0x10            /*PED Busy*/
#define KEYSYS_STS_CURR                         0x20            /*PED current key set */

/* --- Structure of Fix Key & Master/Transaction Key --- */
typedef struct {
        uint8_t mstkey[DES3_KEY_LEN];   /* Master Key */
        uint8_t pinkey[DES3_KEY_LEN];   /* PIN Key */
        uint8_t mackey[DES3_KEY_LEN];   /* MAC Key */
        uint8_t magkey[DES3_KEY_LEN];   /* MAG Key */
        uint8_t lrc[4];
        uint8_t resv[4];
}mst_group_t;

/* --- Structure of DUKPT Key --- */
typedef struct {
        uint8_t key[DES3_KEY_LEN];
        uint8_t lrc;
}des_key_t;

typedef struct {
        uint8_t ksn[DUKPT_KSN_LEN];         /*Key serial Number */
        des_key_t key[DUKPT_SET_MAX];      /*21 future keys*/
        uint8_t resv[1];
}dukpt_group_t;

#define KEYMGT_RESV_SIZE		( 4 - ( 2 + MT_GRP_MAX + FIX_GRP_MAX + \
								DUKPT_GRP_MAX * 3 + MAX_GRP_LEN ) % 4 )
typedef struct {
        uint8_t magic[4];           /*PED Key System Initialization Flags
                                          if !=0x5AA5AA55 PED locked */
        uint8_t ped_pri[256];       /*Private Key of PED*/
        uint8_t ped_kek[DES3_KEY_LEN];        /*key encryption key for keys in Flash*/
        uint8_t hash_chk[32];       /*SH256 check value of current key group*/
        uint8_t cur_fid;            /*current field ID*/
        uint8_t cur_gid;            /*current group ID*/

        uint8_t pin_cnt;            /*PIN crypto counter per hour*/
        uint8_t mac_cnt;            /*MAC calculation counter per hour*/
        uint8_t key_cnt;            /*The application key updating counter per hour*/
		uint8_t mag_cnt;            /*MAg calculation counter per hour*/
        uint32_t pin_cnt_secs;      /*The last PIN_Couter reset time (by seconds)*/
        uint32_t mac_cnt_secs;      /*The last MAC_Couter reset time (by seconds)*/
        uint32_t key_cnt_secs;      /*The last key_Couter reset time (by seconds)*/
		uint32_t mag_cnt_secs;      /*The last MAC_Couter reset time (by seconds)*/
        uint8_t keysys_status;      /*b0 = 0: Self-test passed, 1: Self-test failed
                                      b1 = 0: no CRL, 1: CRL exist
                                      b2 = 0: no session, 1: a session started 
                                      b3 = 1: key LRC check error 
                                      b4 = 1: ped busy now
                                      b5 = 1: current key group had been set */

        uint8_t mt_status[MT_GRP_MAX];          /*Master Key Group status bytes*/
        uint8_t fix_status[FIX_GRP_MAX];        /*Fixed Key Group status bytes*/
        uint8_t dukpt_status[DUKPT_GRP_MAX][3]; /* DUKPT Group status bytes*/

        uint8_t cur_key_group[MAX_GRP_LEN];     /*The current selected key group value (plain-text)*/
        uint8_t session_key[DES3_KEY_LEN];
		uint8_t cur_ksn[DUKPT_KSN_LEN];
		uint8_t cur_dukpt[DES3_KEY_LEN];		//save this transaction dukpt key
		uint8_t resv[KEYMGT_RESV_SIZE];			//resv
}keymgt_t;


#define KEYMGT_ERR_LOCK                 -1          /*key locked*/
#define KEYMGT_ERR_PARA                 -2          /*Parameter error*/
#define KEYMGT_ERR_KEYEMP               -3          /*Key not exist */
#define KEYMGT_ERR_KEYLRC               -4          /*Key LRC error */
#define KEYMGT_ERR_KEYDUP               -5          /*Key reduplicate */
#define KEYMGT_ERR_NOMSTK               -6          /*no Master Key */
#define KEYMGT_ERR_DATALEN              -7          /*data len error */
#define KEYMGT_ERR_DATA                 -8          /*data error */
#define KEYMGT_ERR_ARQRSP               -9          /*arq protocol fram not succ */
#define KEYMGT_ERR_TIMEOUT              -10         /*communication Timeout */
#define KEYMGT_ERR_ARQCOM               -11         /*arq communication Fail */
#define KEYMGT_ERR_PKRECV               -12         /*PK Recover Fail */
#define KEYMGT_ERR_RSA                  -13         /*RSA encrypt/decrypt Fail */
#define KEYMGT_ERR_TR31                 -14         /*TR31 Decode Fail */
#define KEYMGT_ERR_KEYCNT               -15         /*DES Key count exceed */
#define KEYMGT_ERR_KEYSAVE              -16         /* Key set error */
#define KEYMGT_ERR_QUIT                 -17         /* communication quit */
#define KEYMGT_ERR_STIMEOUT             -18         /*session key Timeout */
#define KEYMGT_ERR_SETGRP               -19         /*set key group error */
#define KEYMGT_ERR_NOAUTH               -20         /*no multual authentication */

#define MGT_MAGIC_UNLOCK                "\xA5\x5A\xAA\x55"      /*magic unlocked value */
#define MGT_MAGIC_LEN                   4

/* ARQ protocol frame definition */
#define ARQ_RSP_SUCC            0x00            /*data correct*/
#define ARQ_RSP_START           0x01            /*communication start*/
#define ARQ_RSP_END             0x02            /*communication end*/
#define ARQ_RSP_DATA_ERR        0x03            /*data error*/
#define ARQ_RSP_SSK_TIMEOUT     0x04            /*session key invalid*/
#define ARQ_RSP_PK_REVOKE       0x05            /*publick RSA key revoke*/
#define ARQ_RSP_ARQ_TIMEOUT     0x06            /*wait timeout*/
#define ARQ_RSP_ARQ_SAVEFAIL    0x07            /*save key fail*/
#define ARQ_RSP_ARQ_KEYDUP      0x08            /*key duplicate*/
#define ARQ_RSP_ARQ_CNTOVER     0x09            /*key injection count exceed*/
#define ARQ_RSP_DATALEN_ERR     0x0A            /*data len error*/
#define ARQ_RSP_PK_ENCRYPT      0x0B
#define ARQ_RSP_TR31_FORMAT     0x0C
#define ARQ_RSP_CERT_REC_ERR    0x0D

#define ARQ_PROF_LEN            1               /* ARQ protocol frame byte */

#define COM_TIMEOUT             (30000)                 /* 30s */
#define HOUR_SECS               (60*60)
#define COUNT_PER_HOUR_PIN      120             /*allow 120 times encryption per hour */
#define COUNT_PER_HOUR_MAC      240             /*allow 240 times encryption per hour */
#define COUNT_PER_HOUR_MAG      120             /*allow 120 times encryption per hour */
#define COUNT_PER_HOUR_KEY      30              /*allow 30 times encryption per hour */
#define SESSION_KEY_LIFETIME    (60*5)          /*session key lifetime 5mins,invalid if exceed*/
#define MAND_SELFTEST_TIME      (HOUR_SECS*12 ) /*mandatory security selftest after 12 hours*/

// definition of type
#define PIN_CNT				0x00			/*PIN encrypt counter per hour*/
#define MAC_CNT				0x01			/*MAC encryp counter per hour*/
#define KEY_CNT				0x02			/*Key update counter per hour*/
#define MAG_CNT				0x03			/*MAC encryp counter per hour..?*/
extern int check_secs( int type );


/**----------------PIN & MAC operation--------------------**/
//mac_x919 Function
extern int mac_x919(uint8_t* in, uint32_t len, uint8_t *out);

//pin encrypt Function
typedef enum{
	ISO9564_FORMAT0,
	ISO9564_FORMAT1,
	ISO9564_FORMAT2,		//offline pin
	ISO9564_FORMAT3,
	ISO9564_BLKTYPE,
}pin_block_type_t;

#define MIN_PAN_LEN 	12 //min_pan_len 12bytes


typedef struct{
	uint8_t * pin;				//pin		the input pin string
	uint32_t pinlen;				//pinlen	the pin length
	uint8_t * pan;				//pan		the PAN
	uint32_t panlen;				//panlen	PAN length
	R_RSA_PUBLIC_KEY * key;		//key     ISO9564_FORMAT2(Offline PIN) -> RSA key, or not exist
	uint8_t iscipher;			/*isencrypt	ISO9564_FORMAT2  	
											1: cipher pin
											0: plain-text pin*/
	uint8_t resv[3];
}pin_encrypt_t;
/*	Func:	encrypt personal PIN 
 *	Para:	
 *			format	the format type of ISO9564
 *			result	ISO9564_FORMAT2(Online PIN) -> the enciphered pinlbock
 *					Offline PIN -> returned status value of PIN verify APDU 
 *	Return:	0		succ
 *			other	fail
 */
extern int pins_encrypt( pin_block_type_t format, pin_encrypt_t *info, 
														uint8_t * result);

extern int get_keygrp_no( uint8_t *fid, uint8_t *gid );
extern int set_curr_keygrp( uint8_t fid, uint8_t gid );
extern int mutual_auth( void );
extern int crl_injection( void );
extern int key_injection( void );

#endif /* KEYMGT_H_ */
